//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


#include <stdio.h>
#include <string.h>
#include "Config.h"
#include "Terrain.h"
#include "Images/Image.h"
#include "Vetor3D.h"
#include <math.h>


#define FENCE(x, l, h) (x > l ? (x < h ? x : h) : l)
#define FLOAT_MAX 3.402823466e+38F
#define WALL_HEIGHT 5.0f
#define MODEL_HEIGHT 1.0f


//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CTerrain::CTerrain() {

  m_nWidth = 0;
  m_nDepth = 0;
  m_pfTerrain = NULL;
  m_pfNormals = NULL;
  m_pszWalls  = NULL;
  m_nTexture = 0;
  m_nWallTexture = 0;
}


//-----------------------------------------------------------------------------
// destructor
//-----------------------------------------------------------------------------
CTerrain::~CTerrain() {

  // aux vars
  map<int, CModelAl *>::iterator itpoEnemy;

  if (m_pfTerrain) {

    delete[] m_pfTerrain;
    m_pfTerrain = NULL;
  }

  if (m_pfNormals) {

    delete[] m_pfNormals;
    m_pfNormals = NULL;
  }

  if (m_pszWalls) {

    delete[] m_pszWalls;
    m_pszWalls = NULL;
  }

  if (m_nTexture) {

    glDeleteTextures(1, &m_nTexture);
    m_nTexture = 0;
  }

  if (m_nWallTexture) {

    glDeleteTextures(1, &m_nWallTexture);
    m_nWallTexture = 0;
  }

  for (itpoEnemy = m_mnpoEnemies.begin(); itpoEnemy != m_mnpoEnemies.end(); itpoEnemy++)
    delete itpoEnemy->second;
  m_mnpoEnemies.clear();
}


//-----------------------------------------------------------------------------
// initialize the terrain
//-----------------------------------------------------------------------------
bool CTerrain::Init(const char *pszFilename, const char *pszTexture,
                    const char *pszWalls, const char *pszWallTexture, float fScale) {

  //aux vars
  CImage oImage, oTexture, oWalls;
  unsigned char *pszImageBuffer;
  int nAux, nIdx, nDX, nDZ;
  GLenum eTexFormat;

  oImage.Init();
  if (!oImage.Load(pszFilename))
    return false;

  m_nWidth = oImage.GetWidth();
  m_nDepth = oImage.GetHeight();

  nDX = m_nWidth / 2;
  nDZ = m_nDepth / 2;

  m_pfTerrain = new float[m_nWidth * m_nDepth];
  m_pfNormals = new float[m_nWidth * m_nDepth * 3];

  pszImageBuffer = (unsigned char *)oImage.GetImage();

  //load height field
  for (nIdx = 0; nIdx < m_nWidth * m_nDepth; nIdx++) {

    nAux = ((*pszImageBuffer) << 16) | ((*(pszImageBuffer + 1)) << 8) | (*(pszImageBuffer + 2));
    nAux -= (1 << 24);

    m_pfTerrain[nIdx] = ((float) nAux / (float)(1 << 24)) * fScale;

    pszImageBuffer +=3;
  }

  //load texture
  oTexture.Init();
  if (!oTexture.Load(pszTexture))
    return false;

  switch (oTexture.GetChannels()) {

    case 1:
      eTexFormat = GL_R;
      break;

    case 2:
      eTexFormat = GL_LUMINANCE_ALPHA;
      break;

    case 3:
      eTexFormat = GL_RGB;
      break;

    case 4:
      eTexFormat = GL_RGBA;
      break;

    default:
      cerr << "ERROR: could not find the PNG image buffer format: " << oTexture.GetChannels() << endl;
  }

  glGenTextures(1, &m_nTexture);
  glBindTexture(GL_TEXTURE_2D, m_nTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, oTexture.GetWidth(), oTexture.GetHeight(), 0, eTexFormat, GL_UNSIGNED_BYTE, oTexture.GetImage());

  if (glGetError() != GL_NO_ERROR) {

    cerr << "ERROR: OGL error loading terrain texture!" << endl;
    exit(0);
  }

	//load walls
	oWalls.Init();
	if (!oWalls.Load(pszWalls))
	return false;

	m_pszWalls = new unsigned char[m_nWidth * m_nDepth];

	pszImageBuffer = (unsigned char *)oWalls.GetImage();
	
	for (nIdx = 0; nIdx < m_nWidth * m_nDepth; nIdx++) {

		nAux = ((*pszImageBuffer) << 16) | ((*(pszImageBuffer + 1)) << 8) | (*(pszImageBuffer + 2));
		m_pszWalls[nIdx] = TERRAIN_EMPTY;
		if (nAux == 16711680){
			m_pszWalls[nIdx] = TERRAIN_WALL;
		} else if (nAux==255){ //Tarefa 3 //load enemies
			m_pszWalls[nIdx] = TERRAIN_ENEMY;
			CModelAl *cmodel = new CModelAl();
			cmodel->Init();
			cmodel->Translate((float)(nIdx%m_nWidth - nDX), m_pfTerrain[nIdx]+MODEL_HEIGHT, (float)(nIdx/m_nWidth - nDZ));			
			cmodel->RotateY(rand()%360);
			m_mnpoEnemies.insert( pair<int,CModelAl *>(nIdx, cmodel)  );
		}
		pszImageBuffer +=3;
	}
	
	
	//load wall texture
  oTexture.Init();
  if (!oTexture.Load(pszWallTexture))
    return false;

  switch (oTexture.GetChannels()) {

    case 1:
      eTexFormat = GL_R;
      break;

    case 2:
      eTexFormat = GL_LUMINANCE_ALPHA;
      break;

    case 3:
      eTexFormat = GL_RGB;
      break;

    case 4:
      eTexFormat = GL_RGBA;
      break;

    default:
      cerr << "ERROR: could not find the PNG image buffer format: " << oTexture.GetChannels() << endl;
  }

  glGenTextures(1, &m_nWallTexture);
  glBindTexture(GL_TEXTURE_2D, m_nWallTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, oTexture.GetWidth(), oTexture.GetHeight(), 0, eTexFormat, GL_UNSIGNED_BYTE, oTexture.GetImage());

  if (glGetError() != GL_NO_ERROR) {

    cerr << "ERROR: OGL error loading terrain texture!" << endl;
    exit(0);
  }

  return true;
}


//-----------------------------------------------------------------------------
// return the height of a given spatial position
//-----------------------------------------------------------------------------
float CTerrain::GetTerrainHeight(float fUserX, float fUserZ) {
  return m_pfTerrain[toIdx(fUserX, fUserZ)]+MODEL_HEIGHT+1.0f;//tarefa 1
}


void drawCube(){
	glNormal3f(0.0f, 1.0f, 0.0f);
	glBegin ( GL_QUADS );
		// Face frontal
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		// Face posterior
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		// Face superior
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		// Face inferior
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		// Face lateral direita
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		// Face lateral esquerda
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
	glEnd();
}


#define intsToIdx(x, z) ((z) * m_nWidth + x)
//-----------------------------------------------------------------------------
// draw terrain
//-----------------------------------------------------------------------------
void CTerrain::Draw() {

  // aux vars
  int nX, nZ, nIdx, nDX, nDZ;
  float afSpecular[] = {0.0f, 0.0f, 0.0f, 1.0f};
  float fShininess = 0.0f, fTextureRepeat;
  float afAmbientAndDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
  map<int, CModelAl *>::iterator itpoEnemy;

  glPushAttrib(GL_ALL_ATTRIB_BITS);

  // draw terrain
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, m_nTexture);
  glEnable(GL_NORMALIZE);

  glMaterialfv(GL_FRONT, GL_SPECULAR, afSpecular);
  glMaterialf(GL_FRONT, GL_SHININESS, fShininess);
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, afAmbientAndDiffuse);

  nDX = m_nWidth / 2;
  nDZ = m_nDepth / 2;

  fTextureRepeat = 50;

  for (nZ = 0; nZ < m_nDepth - 1; nZ++) {

    glBegin(GL_TRIANGLE_STRIP);
    glNormal3f(0.0f, 1.0f, 0.0f);

    for (nX = 0; nX < m_nWidth; nX++) {

      nIdx = nZ * m_nWidth + nX;
      glTexCoord2f((float)(nX - nDX) / fTextureRepeat, (float)(nZ - nDZ) / fTextureRepeat);
      glVertex3f((float)(nX - nDX), m_pfTerrain[nIdx], (float)(nZ - nDZ));
      nIdx += m_nWidth;
      glTexCoord2f((float)(nX - nDX) / fTextureRepeat, (float)(nZ + 1 - nDZ) / fTextureRepeat);
      glVertex3f((float)(nX - nDX), m_pfTerrain[nIdx], (float)(nZ + 1 - nDZ));
      
    }

    glEnd();
  }

  glBindTexture(GL_TEXTURE_2D, 0);
  
  
  glFlush();
  /* tarefa 2: textura muros */
  glBindTexture(GL_TEXTURE_2D, m_nWallTexture);
  glEnable(GL_NORMALIZE);


   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
   glBindTexture(GL_TEXTURE_2D, m_nWallTexture);
/*
  glMaterialfv(GL_FRONT, GL_SPECULAR, afSpecular);
  glMaterialf(GL_FRONT, GL_SHININESS, fShininess);
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, afAmbientAndDiffuse);*/

  nDX = m_nWidth / 2;
  nDZ = m_nDepth / 2;

  fTextureRepeat = 40;
	int befWall = 0;
	int nY=0;
  for (nZ = 0; nZ < m_nDepth - 1; nZ++) {
	/*if (befWall){
		befWall =0;
		continue;
	}*/
    for (nX = 0; nX < m_nWidth; nX++) {

      nIdx = nZ * m_nWidth + nX;
      /*if (!makingwall && m_pszWalls[nIdx]){
    	glBegin(GL_QUAD_STRIP);
    	glNormal3f(0.0f, 1.0f, 0.0f);
    	makingwall = 1;
      }*/
      if ((m_pszWalls[nIdx] == TERRAIN_WALL) && (m_pszWalls[nZ * m_nWidth + nX + 1] == TERRAIN_WALL) && (m_pszWalls[(nZ+1) * m_nWidth + nX] == TERRAIN_WALL)){
      
      
      
	glBegin ( GL_QUADS );
		// Face frontal(float)(nX - nDX), m_pfTerrain[nIdx], (float)(nZ - nDZ)
      	glNormal3f(0.0f, 0.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ + 1)],  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ + 1)],  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		glTexCoord2f(0.0f, 1.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		// Face posterior
      	glNormal3f(0.0f, 0.0f, 1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ)], (float)(nZ - nDZ));
		glTexCoord2f(1.0f, 1.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ)], (float)(nZ - nDZ));
		// Face superior
      	glNormal3f(0.0f, 1.0f, 0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 0.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		// Face inferior
      	glNormal3f(0.0f, -1.0f, 0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ)], (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ)], (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ + 1)],  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 0.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ + 1)],  (float)(nZ - nDZ + 1));
		// Face lateral direita
      	glNormal3f(1.0f, 0.0f, 0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ)], (float)(nZ - nDZ));
		glTexCoord2f(1.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		glTexCoord2f(0.0f, 1.0f); glVertex3f( (float)(nX - nDX + 1),  (float)(m_pfTerrain[intsToIdx(nX + 1, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		glTexCoord2f(0.0f, 0.0f); glVertex3f( (float)(nX - nDX + 1), m_pfTerrain[intsToIdx(nX + 1, nZ + 1)],  (float)(nZ - nDZ + 1));
		// Face lateral esquerda
      	glNormal3f(-1.0f, 0.0f, 0.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ)], (float)(nZ - nDZ));
		glTexCoord2f(1.0f, 0.0f); glVertex3f((float)(nX - nDX), m_pfTerrain[intsToIdx(nX, nZ + 1)],  (float)(nZ - nDZ + 1));
		glTexCoord2f(1.0f, 1.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ + 1)]+WALL_HEIGHT),  (float)(nZ - nDZ + 1));
		glTexCoord2f(0.0f, 1.0f); glVertex3f((float)(nX - nDX),  (float)(m_pfTerrain[intsToIdx(nX, nZ)]+WALL_HEIGHT), (float)(nZ - nDZ));
		
	glEnd();
      
      
      
      
      
      
      
      
/*      	for (nY = m_pfTerrain[nIdx]+(int)WALL_HEIGHT+1; nY--; )*/{
 			/*glPushMatrix(); // Peh
      			glTranslatef ((float)(nX - nDX), m_pfTerrain[nIdx]+nY, (float)(nZ - nDZ));
      			glScalef(1.0, (float)WALL_HEIGHT, 1.0);
			  drawCube();
//			  glutSolidCube(1.0);
			glPopMatrix();*/
      	
      	}
	  }
      
    }
    
  }

  glBindTexture(GL_TEXTURE_2D, 0);
  /* fim tarefa 2 */
  
  glDisable(GL_TEXTURE_2D);
//	int nX, nZ, nIdx;
	float *modelPos; int rv; float angle, intens = 0.1f;
	float newPos[3];
  for (itpoEnemy = m_mnpoEnemies.begin(); itpoEnemy != m_mnpoEnemies.end(); itpoEnemy++){
  	if (!itpoEnemy->second->isDying()){
  		rv = rand();
  		angle = itpoEnemy->second->getAngle();
		modelPos = itpoEnemy->second->getPosition();
  		/*angle = acosf(modelPos[0]/sqrt(pow(modelPos[0], 2)+pow(modelPos[2], 2)));
  		cout << angle << endl;
	  	//itpoEnemy->second->RotateY(angle);
*/
  		//cout << angle << endl;
  		if (rv%100<5) //rotate model with a chance of 5%
		  if (angle>360.0f)
		  	itpoEnemy->second->RotateY(-(float)(rv%90-45));
		  else //if (angle<-360.0f)
		  	itpoEnemy->second->RotateY((float)(rv%90-45));
  		angle = itpoEnemy->second->getAngle();  		
		newPos[0] = modelPos[0]+sin(angle)*intens;
		newPos[2] = modelPos[2]+cos(angle)*intens; 
		
		if ((fabs((int)newPos[0]) < m_nWidth/2 && fabs((int)newPos[2] < m_nDepth/2) && m_pszWalls[toIdx(newPos[0], newPos[2])]!=TERRAIN_WALL)){
			m_pszWalls[toIdx(modelPos[0], modelPos[2])] = TERRAIN_EMPTY;
			m_pszWalls[toIdx(newPos[0], newPos[2])] = TERRAIN_ENEMY;
			itpoEnemy->second->Translate(newPos[0], GetTerrainHeight(newPos[0], newPos[2])-1.0f, newPos[2]);
		} else
  			itpoEnemy->second->RotateY(90.0f);
//		cout << "angle: " << angle << "\tcos: " << cos(angle) << "\tsin: " << sin(angle) <<endl;
    }
    itpoEnemy->second->Draw();
  }

  glPopAttrib();
}

//-----------------------------------------------------------------------------
// validate position
//-----------------------------------------------------------------------------
bool CTerrain::ValidatePosition(float fX, float fZ) {
	//verifica se não há muro nem inimigo nessa posição	
  return fabs((int)fX) < m_nWidth/2 && fabs((int)fZ < m_nDepth/2) && !m_pszWalls[toIdx(fX, fZ)];//TODO: tarefa 2
}


//-----------------------------------------------------------------------------
// check collision
//-----------------------------------------------------------------------------
float CTerrain::CheckCollisionRay(float *pfPosition, float *pfDirection) {

    float afPercurso[3];
    float distancia;
    float x,y,z;
    float distAl;
    afPercurso[0] = pfPosition[0];
    afPercurso[1] = pfPosition[1];
    afPercurso[2] = pfPosition[2];
    int percursoIdx;
    map<int, CModelAl *>::iterator itpoEnemy;
   

    distancia = -1.0f;
    int nX, nZ;
    while (fabs((int)afPercurso[0]) < m_nWidth/2 && fabs((int)afPercurso[2] < m_nDepth/2)) {
    
		nX = afPercurso[0] + m_nWidth / 2;
		nZ = afPercurso[2] + m_nDepth / 2;

        percursoIdx = nZ * m_nWidth + nX;//(int)afPercurso[0] * (int)afPercurso[2];
        //printf ("rodada x:%d y:%d z:%d\n",(int)nX, (int)m_pfTerrain[percursoIdx], (int)nZ);
		//percursoIdx = (int)(afPercurso[2] + m_nDepth / 2) * m_nWidth + (int)(afPercurso[0] + m_nWidth / 2);


       //verifica se bate no Al
        //getchar(); + scanf("c\n");
        distAl = -1.0f;
        for (itpoEnemy = m_mnpoEnemies.begin(); itpoEnemy != m_mnpoEnemies.end(); itpoEnemy++) {
            distAl = itpoEnemy->second->CheckCollisionRay(pfPosition,afPercurso);
            if (distAl > -1.0f) {
                    distancia = distAl;
                    goto end;
            }
        }

		//verifica se bate no muro
        if (m_pszWalls[percursoIdx] && afPercurso[1]<WALL_HEIGHT+m_pfTerrain[percursoIdx]){
            //printf ("HIT Wall: %f %f %f > %f \n",afPercurso[0],afPercurso[1],afPercurso[2],m_pfTerrain[percursoIdx]);
            x = afPercurso[0] - pfPosition[0];
            y = afPercurso[1] - pfPosition[1];
            z = afPercurso[2] - pfPosition[2];
            //distancia entre dois pontos 3d
            distancia = sqrt(pow(x,2)+pow(y,2)+pow(z,2));
            break;
        }

        //verifica se bate no terreno
        if ((int)afPercurso[1] == (int)m_pfTerrain[percursoIdx]){
            //printf ("HIT Terrain: %f %f %f > %f \n",afPercurso[0],afPercurso[1],afPercurso[2],m_pfTerrain[percursoIdx]);
            x = afPercurso[0] - pfPosition[0];
            y = m_pfTerrain[percursoIdx] - pfPosition[1];
            z = afPercurso[2] - pfPosition[2];
            //distancia entre dois pontos 3d
            distancia = sqrt(pow(x,2)+pow(y,2)+pow(z,2));
            break;
        }

       if (distAl > -1.0f) {
               distancia = distAl;
               break;
       }
       
        //cuidar depois excecao onde direcao de x e z eh 0
        afPercurso[0] += pfDirection[0];
        afPercurso[1] += pfDirection[1];
        afPercurso[2] += pfDirection[2];
    }
    end:
    //printf ("distancia da colisao: %f\n",distancia);
    return distancia;
}
